{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import absolute_import, division, print_function, unicode_literals\n",
    "\n",
    "%matplotlib inline\n",
    "%reload_ext autoreload\n",
    "%autoreload 2\n",
    "\n",
    "\n",
    "import itertools as it\n",
    "import multiprocessing as mp\n",
    "\n",
    "from typing import List, Tuple, Generator, Iterator\n",
    "\n",
    "import numpy as np\n",
    "SEED = 0x1234\n",
    "np.random.seed(SEED)\n",
    "np.set_printoptions(suppress=True)\n",
    "\n",
    "import scipy as sp\n",
    "from scipy import stats, optimize\n",
    "\n",
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%config InlineBackend.figure_format =  'png'\n",
    "\n",
    "import seaborn as sns\n",
    "\n",
    "import pandas as pd\n",
    "pd.set_option('display.max_rows', 999)\n",
    "pd.set_option('display.max_columns', 999)\n",
    "pd.set_option('precision', 3)\n",
    "\n",
    "import sklearn as skl\n",
    "\n",
    "import ipywidgets as widgets\n",
    "from ipywidgets import interact\n",
    "\n",
    "from pprint import pprint\n",
    "\n",
    "import joblib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Helpers\n",
    "def latexify(fig_width=None, fig_height=None, columns=1, scale=1.0):\n",
    "    from math import sqrt\n",
    "    \"\"\"Set up matplotlib's RC params for LaTeX plotting.\n",
    "    Call this before plotting a figure.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    fig_width : float, optional, inches\n",
    "    fig_height : float,  optional, inches\n",
    "    columns : {1, 2}, how many columns it covers\n",
    "    \"\"\"\n",
    "\n",
    "    # code adapted from http://www.scipy.org/Cookbook/Matplotlib/LaTeX_Examples\n",
    "\n",
    "    # Width and max height in inches for IEEE journals taken from\n",
    "    # computer.org/cms/Computer.org/Journal%20templates/transactions_art_guide.pdf\n",
    "\n",
    "    assert(columns in [1,2])\n",
    "    \n",
    "    #width  = 3.487\n",
    "    #height = width / 1.618\n",
    "\n",
    "    if fig_width is None:\n",
    "        fig_width = 3.39 if columns==1 else 6.9 # width in inches\n",
    "\n",
    "    if fig_height is None:\n",
    "        golden_mean = (sqrt(5) - 1.0) / 2.0    # Aesthetic ratio\n",
    "        fig_height = fig_width * golden_mean # height in inches\n",
    "        \n",
    "        \n",
    "    fig_height *= scale\n",
    "    fig_width *= scale\n",
    "\n",
    "    MAX_HEIGHT_INCHES = 16.0 * scale\n",
    "    if fig_height > MAX_HEIGHT_INCHES:\n",
    "        print(\"WARNING: fig_height too large:\" + fig_height + \n",
    "              \"so will reduce to\" + MAX_HEIGHT_INCHES + \"inches.\")\n",
    "        fig_height = MAX_HEIGHT_INCHES\n",
    "\n",
    "    params = {\n",
    "        # Use LaTex to write all text\n",
    "        'text.usetex': True,\n",
    "        'font.family': 'serif',\n",
    "        #'font.serif': 'Times',\n",
    "        # Use 10pt font in plots, to match 10pt font in document\n",
    "        #'axes.labelsize': 10,\n",
    "        #'font.size': 10,\n",
    "        # Make the legend/label fonts a little smaller\n",
    "        #'legend.fontsize': 8,\n",
    "        #'xtick.labelsize': 8,\n",
    "        #'ytick.labelsize': 8,\n",
    "        \n",
    "        'figure.autolayout': True,\n",
    "        'figure.figsize': [fig_width, fig_height],\n",
    "        \n",
    "        'savefig.format': 'pdf',\n",
    "        'savefig.bbox': 'tight',\n",
    "        \n",
    "        'pdf.fonttype': 42,\n",
    "        \n",
    "        #'legend.framealpha': 0.2,\n",
    "        \n",
    "        'grid.color': '0.9',\n",
    "        'grid.linestyle': ':',\n",
    "    }\n",
    "    \n",
    "    mpl.style.use('default')\n",
    "    mpl.style.use(['seaborn-notebook', 'seaborn-whitegrid', 'seaborn-ticks'])\n",
    "    mpl.rcParams.update(params)\n",
    "    \n",
    "\n",
    "def set_size(width, fraction=1):\n",
    "    from math import sqrt\n",
    "    # SRC: https://jwalton.info/Embed-Publication-Matplotlib-Latex/\n",
    "    \n",
    "    # 252.0pt is IEEEtrans columnwidth (\\showthe\\columnwidth)\n",
    "    \n",
    "    \n",
    "    if width == 'thesis':\n",
    "        width_pt = 426.79135\n",
    "    elif width == 'beamer':\n",
    "        width_pt = 307.28987\n",
    "    elif width == 'pnas':\n",
    "        width_pt = 246.09686\n",
    "    else:\n",
    "        width_pt = width\n",
    "    \n",
    "    fig_width_pt = width_pt * fraction\n",
    "    inches_per_pt = 1.0 / 72.27\n",
    "    golden_ratio = (sqrt(5) - 1.0) / 2.0\n",
    "    \n",
    "    fig_width_in = fig_width_pt * inches_per_pt\n",
    "    fig_height_in = fig_width_in * golden_ratio\n",
    "    fig_dim = (fig_width_in, fig_height_in)\n",
    "    return fig_dim\n",
    "\n",
    "\n",
    "def format_axes(ax, SPINE_COLOR='gray', despine=False):\n",
    "    \n",
    "    if despine:\n",
    "        for spine in ['top', 'right']:\n",
    "            ax.spines[spine].set_visible(False)\n",
    "        \n",
    "\n",
    "    for spine in ['left', 'bottom', 'top', 'right']:\n",
    "        ax.spines[spine].set_color(SPINE_COLOR)\n",
    "        ax.spines[spine].set_linewidth(0.5)\n",
    "\n",
    "    #ax.xaxis.set_ticks_position('bottom')\n",
    "    #ax.yaxis.set_ticks_position('left')\n",
    "\n",
    "    for axis in [ax.xaxis, ax.yaxis]:\n",
    "        axis.set_tick_params(direction='out', color=SPINE_COLOR)\n",
    "\n",
    "    return ax\n",
    "\n",
    "\n",
    "def ensure_dir(path: str):\n",
    "    from pathlib import Path\n",
    "    _path = Path(path)\n",
    "    _path.parent.mkdir(parents=True, exist_ok=True)\n",
    "    return path\n",
    "\n",
    "\n",
    "latexify(columns=2)\n",
    "\n",
    "memory = joblib.Memory(location='.cache', verbose=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>rssi</th>\n",
       "      <th>received</th>\n",
       "      <th>error</th>\n",
       "      <th>seq</th>\n",
       "      <th>noise</th>\n",
       "      <th>src</th>\n",
       "      <th>dst</th>\n",
       "      <th>srcRow</th>\n",
       "      <th>srcCol</th>\n",
       "      <th>dstRow</th>\n",
       "      <th>dstCol</th>\n",
       "      <th>rss</th>\n",
       "      <th>d</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>125577</th>\n",
       "      <td>0</td>\n",
       "      <td>False</td>\n",
       "      <td>False</td>\n",
       "      <td>177</td>\n",
       "      <td>-10</td>\n",
       "      <td>(5.0, 6.0)</td>\n",
       "      <td>(1.0, 4.0)</td>\n",
       "      <td>5.0</td>\n",
       "      <td>6.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>4.0</td>\n",
       "      <td>-95.0</td>\n",
       "      <td>4.472</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>156939</th>\n",
       "      <td>0</td>\n",
       "      <td>False</td>\n",
       "      <td>False</td>\n",
       "      <td>39</td>\n",
       "      <td>-10</td>\n",
       "      <td>(6.0, 7.0)</td>\n",
       "      <td>(8.0, 1.0)</td>\n",
       "      <td>6.0</td>\n",
       "      <td>7.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>-95.0</td>\n",
       "      <td>6.325</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>657373</th>\n",
       "      <td>0</td>\n",
       "      <td>False</td>\n",
       "      <td>False</td>\n",
       "      <td>73</td>\n",
       "      <td>-20</td>\n",
       "      <td>(5.0, 6.0)</td>\n",
       "      <td>(6.0, 1.0)</td>\n",
       "      <td>5.0</td>\n",
       "      <td>6.0</td>\n",
       "      <td>6.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>-95.0</td>\n",
       "      <td>5.099</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>858876</th>\n",
       "      <td>0</td>\n",
       "      <td>False</td>\n",
       "      <td>False</td>\n",
       "      <td>276</td>\n",
       "      <td>-5</td>\n",
       "      <td>(5.0, 6.0)</td>\n",
       "      <td>(1.0, 6.0)</td>\n",
       "      <td>5.0</td>\n",
       "      <td>6.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>6.0</td>\n",
       "      <td>-95.0</td>\n",
       "      <td>4.000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>175641</th>\n",
       "      <td>15</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>141</td>\n",
       "      <td>-10</td>\n",
       "      <td>(8.0, 3.0)</td>\n",
       "      <td>(7.0, 6.0)</td>\n",
       "      <td>8.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>7.0</td>\n",
       "      <td>6.0</td>\n",
       "      <td>-80.0</td>\n",
       "      <td>3.162</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1051788</th>\n",
       "      <td>8</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>288</td>\n",
       "      <td>-15</td>\n",
       "      <td>(1.0, 2.0)</td>\n",
       "      <td>(1.0, 6.0)</td>\n",
       "      <td>1.0</td>\n",
       "      <td>2.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>6.0</td>\n",
       "      <td>-87.0</td>\n",
       "      <td>4.000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1075047</th>\n",
       "      <td>0</td>\n",
       "      <td>False</td>\n",
       "      <td>False</td>\n",
       "      <td>147</td>\n",
       "      <td>-15</td>\n",
       "      <td>(8.0, 1.0)</td>\n",
       "      <td>(5.0, 8.0)</td>\n",
       "      <td>8.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>5.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-95.0</td>\n",
       "      <td>7.616</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>608505</th>\n",
       "      <td>0</td>\n",
       "      <td>False</td>\n",
       "      <td>False</td>\n",
       "      <td>105</td>\n",
       "      <td>-20</td>\n",
       "      <td>(7.0, 4.0)</td>\n",
       "      <td>(1.0, 8.0)</td>\n",
       "      <td>7.0</td>\n",
       "      <td>4.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-95.0</td>\n",
       "      <td>7.211</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>133045</th>\n",
       "      <td>10</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>145</td>\n",
       "      <td>-10</td>\n",
       "      <td>(5.0, 8.0)</td>\n",
       "      <td>(6.0, 3.0)</td>\n",
       "      <td>5.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>6.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>-85.0</td>\n",
       "      <td>5.099</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>319869</th>\n",
       "      <td>0</td>\n",
       "      <td>False</td>\n",
       "      <td>False</td>\n",
       "      <td>69</td>\n",
       "      <td>0</td>\n",
       "      <td>(1.0, 8.0)</td>\n",
       "      <td>(7.0, 4.0)</td>\n",
       "      <td>1.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>7.0</td>\n",
       "      <td>4.0</td>\n",
       "      <td>-95.0</td>\n",
       "      <td>7.211</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "         rssi  received  error  seq  noise         src         dst  srcRow  \\\n",
       "125577      0     False  False  177    -10  (5.0, 6.0)  (1.0, 4.0)     5.0   \n",
       "156939      0     False  False   39    -10  (6.0, 7.0)  (8.0, 1.0)     6.0   \n",
       "657373      0     False  False   73    -20  (5.0, 6.0)  (6.0, 1.0)     5.0   \n",
       "858876      0     False  False  276     -5  (5.0, 6.0)  (1.0, 6.0)     5.0   \n",
       "175641     15      True  False  141    -10  (8.0, 3.0)  (7.0, 6.0)     8.0   \n",
       "1051788     8      True  False  288    -15  (1.0, 2.0)  (1.0, 6.0)     1.0   \n",
       "1075047     0     False  False  147    -15  (8.0, 1.0)  (5.0, 8.0)     8.0   \n",
       "608505      0     False  False  105    -20  (7.0, 4.0)  (1.0, 8.0)     7.0   \n",
       "133045     10      True  False  145    -10  (5.0, 8.0)  (6.0, 3.0)     5.0   \n",
       "319869      0     False  False   69      0  (1.0, 8.0)  (7.0, 4.0)     1.0   \n",
       "\n",
       "         srcCol  dstRow  dstCol   rss      d  \n",
       "125577      6.0     1.0     4.0 -95.0  4.472  \n",
       "156939      7.0     8.0     1.0 -95.0  6.325  \n",
       "657373      6.0     6.0     1.0 -95.0  5.099  \n",
       "858876      6.0     1.0     6.0 -95.0  4.000  \n",
       "175641      3.0     7.0     6.0 -80.0  3.162  \n",
       "1051788     2.0     1.0     6.0 -87.0  4.000  \n",
       "1075047     1.0     5.0     8.0 -95.0  7.616  \n",
       "608505      4.0     1.0     8.0 -95.0  7.211  \n",
       "133045      8.0     6.0     3.0 -85.0  5.099  \n",
       "319869      8.0     7.0     4.0 -95.0  7.211  "
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from datasets.trace1_Rutgers.transform import get_traces, dtypes\n",
    "from datasets.trace1_Rutgers import NOISE_SOURCES\n",
    "\n",
    "coords = Tuple[float, float]\n",
    "\n",
    "def get_distance(points: Tuple[coords,coords]) -> float:\n",
    "    assert len(points) == 2, 'Require exactly 2 points to calculate distance'\n",
    "    (x1, y1), (x2, y2) = points\n",
    "    d = np.sqrt(np.power(x2 - x1, 2) + np.power(y2 - y1, 2))\n",
    "    return d\n",
    "\n",
    "def dbm2mw(value: float) -> float:\n",
    "    return 0.001 * np.power(10, value / 10.)\n",
    "\n",
    "def mw2dbm(value: float) -> float:\n",
    "    return 10. * np.log10(value / 0.001)\n",
    "\n",
    "TX_POWER = 10.0 # dBm\n",
    "RSSI_BASE = -95.0 # dBm; not sure for this one. Most of the Atheros' have -95\n",
    "FREQ = 2450.0 # MHz\n",
    "\n",
    "\n",
    "def rssi2rss(rssi):\n",
    "    return rssi + RSSI_BASE\n",
    "\n",
    "@memory.cache\n",
    "def get_rutgers_datapoints() -> pd.DataFrame:\n",
    "    def name2coords(name: str) -> Tuple[float, float]:\n",
    "        part = name[len('node'):] # extract only numeric part 'node3-2' -> '3-2'\n",
    "        coords = [float(i) for i in part.split('-')]\n",
    "        return tuple(coords)\n",
    "    \n",
    "    df = []\n",
    "    \n",
    "    for trace in get_traces():\n",
    "        src = trace['src'].values[0]\n",
    "        dst = trace['dst'].values[0]\n",
    "        noise = trace['noise'].values[0]\n",
    "\n",
    "        # Fix names\n",
    "        src = name2coords(src)\n",
    "        dst = name2coords(dst)\n",
    "\n",
    "        trace.src = trace.src.apply(name2coords)\n",
    "        trace.dst = trace.dst.apply(name2coords)\n",
    "\n",
    "        # Split column, row\n",
    "        trace['srcRow'], trace['srcCol'] = src\n",
    "        trace['dstRow'], trace['dstCol'] = dst\n",
    "\n",
    "        # Preserve sequence number\n",
    "        trace['seq'] = trace.index\n",
    "\n",
    "        trace['rss'] = trace.rssi + RSSI_BASE\n",
    "\n",
    "        trace['d'] = trace[['src', 'dst']].apply(get_distance, axis=1)\n",
    "\n",
    "        df.append(trace)\n",
    "        \n",
    "    df = pd.concat(df, ignore_index=True)\n",
    "    return df\n",
    "    \n",
    "get_rutgers_datapoints().sample(n=10, random_state=SEED)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>rssi</th>\n",
       "      <th>received</th>\n",
       "      <th>error</th>\n",
       "      <th>seq</th>\n",
       "      <th>noise</th>\n",
       "      <th>src</th>\n",
       "      <th>dst</th>\n",
       "      <th>srcRow</th>\n",
       "      <th>srcCol</th>\n",
       "      <th>dstRow</th>\n",
       "      <th>dstCol</th>\n",
       "      <th>rss</th>\n",
       "      <th>d</th>\n",
       "      <th>meanRSSI</th>\n",
       "      <th>medianRSSI</th>\n",
       "      <th>stdRSSI</th>\n",
       "      <th>PRR</th>\n",
       "      <th>PRR+1</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>14</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>0</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-81.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>11</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>1</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-84.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>7</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>2</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-88.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>6</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>3</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-89.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>5</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>4</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-90.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>8</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>5</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-87.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>4</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>6</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-91.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>8</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>7</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-87.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>6</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>8</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-89.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>6</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>9</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-89.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>7.5</td>\n",
       "      <td>6.5</td>\n",
       "      <td>2.991</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>8</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>10</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-87.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>6.9</td>\n",
       "      <td>6.5</td>\n",
       "      <td>1.969</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>8</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>11</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-87.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>6.6</td>\n",
       "      <td>6.5</td>\n",
       "      <td>1.430</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>7</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>12</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-88.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>6.6</td>\n",
       "      <td>6.5</td>\n",
       "      <td>1.430</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>6</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>13</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-89.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>6.6</td>\n",
       "      <td>6.5</td>\n",
       "      <td>1.430</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>8</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>14</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-87.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>6.9</td>\n",
       "      <td>7.5</td>\n",
       "      <td>1.370</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>9</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>15</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-86.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>7.0</td>\n",
       "      <td>7.5</td>\n",
       "      <td>1.491</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>6</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>16</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-89.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>7.2</td>\n",
       "      <td>7.5</td>\n",
       "      <td>1.135</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>6</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>17</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-89.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>7.0</td>\n",
       "      <td>6.5</td>\n",
       "      <td>1.155</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>6</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>18</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-89.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>7.0</td>\n",
       "      <td>6.5</td>\n",
       "      <td>1.155</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>8</td>\n",
       "      <td>True</td>\n",
       "      <td>False</td>\n",
       "      <td>19</td>\n",
       "      <td>-10</td>\n",
       "      <td>(4.0, 3.0)</td>\n",
       "      <td>(3.0, 8.0)</td>\n",
       "      <td>4.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>3.0</td>\n",
       "      <td>8.0</td>\n",
       "      <td>-87.0</td>\n",
       "      <td>5.099</td>\n",
       "      <td>7.2</td>\n",
       "      <td>7.5</td>\n",
       "      <td>1.135</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    rssi  received  error  seq  noise         src         dst  srcRow  srcCol  \\\n",
       "0     14      True  False    0    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "1     11      True  False    1    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "2      7      True  False    2    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "3      6      True  False    3    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "4      5      True  False    4    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "5      8      True  False    5    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "6      4      True  False    6    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "7      8      True  False    7    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "8      6      True  False    8    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "9      6      True  False    9    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "10     8      True  False   10    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "11     8      True  False   11    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "12     7      True  False   12    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "13     6      True  False   13    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "14     8      True  False   14    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "15     9      True  False   15    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "16     6      True  False   16    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "17     6      True  False   17    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "18     6      True  False   18    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "19     8      True  False   19    -10  (4.0, 3.0)  (3.0, 8.0)     4.0     3.0   \n",
       "\n",
       "    dstRow  dstCol   rss      d  meanRSSI  medianRSSI  stdRSSI  PRR  PRR+1  \n",
       "0      3.0     8.0 -81.0  5.099       NaN         NaN      NaN  NaN    1.0  \n",
       "1      3.0     8.0 -84.0  5.099       NaN         NaN      NaN  NaN    1.0  \n",
       "2      3.0     8.0 -88.0  5.099       NaN         NaN      NaN  NaN    1.0  \n",
       "3      3.0     8.0 -89.0  5.099       NaN         NaN      NaN  NaN    1.0  \n",
       "4      3.0     8.0 -90.0  5.099       NaN         NaN      NaN  NaN    1.0  \n",
       "5      3.0     8.0 -87.0  5.099       NaN         NaN      NaN  NaN    1.0  \n",
       "6      3.0     8.0 -91.0  5.099       NaN         NaN      NaN  NaN    1.0  \n",
       "7      3.0     8.0 -87.0  5.099       NaN         NaN      NaN  NaN    1.0  \n",
       "8      3.0     8.0 -89.0  5.099       NaN         NaN      NaN  NaN    1.0  \n",
       "9      3.0     8.0 -89.0  5.099       7.5         6.5    2.991  1.0    1.0  \n",
       "10     3.0     8.0 -87.0  5.099       6.9         6.5    1.969  1.0    1.0  \n",
       "11     3.0     8.0 -87.0  5.099       6.6         6.5    1.430  1.0    1.0  \n",
       "12     3.0     8.0 -88.0  5.099       6.6         6.5    1.430  1.0    1.0  \n",
       "13     3.0     8.0 -89.0  5.099       6.6         6.5    1.430  1.0    1.0  \n",
       "14     3.0     8.0 -87.0  5.099       6.9         7.5    1.370  1.0    1.0  \n",
       "15     3.0     8.0 -86.0  5.099       7.0         7.5    1.491  1.0    1.0  \n",
       "16     3.0     8.0 -89.0  5.099       7.2         7.5    1.135  1.0    1.0  \n",
       "17     3.0     8.0 -89.0  5.099       7.0         6.5    1.155  1.0    1.0  \n",
       "18     3.0     8.0 -89.0  5.099       7.0         6.5    1.155  1.0    1.0  \n",
       "19     3.0     8.0 -87.0  5.099       7.2         7.5    1.135  1.0    1.0  "
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "@memory.cache\n",
    "def produce_dataset(Wprr:int=10, Wh:int=10, predict_ahead:int=1) -> pd.DataFrame:\n",
    "    \n",
    "    assert isinstance(Wprr, int)\n",
    "    assert isinstance(Wh, int)\n",
    "    assert isinstance(predict_ahead, int)\n",
    "    \n",
    "    def name2coords(name: str) -> Tuple[float, float]:\n",
    "        part = name[len('node'):] # extract only numeric part 'node3-2' -> '3-2'\n",
    "        coords = [float(i) for i in part.split('-')]\n",
    "        return tuple(coords)\n",
    "    \n",
    "    df = []\n",
    "    \n",
    "    for trace in get_traces():\n",
    "        src = trace['src'].values[0]\n",
    "        dst = trace['dst'].values[0]\n",
    "        noise = trace['noise'].values[0]\n",
    "\n",
    "        # Fix names\n",
    "        src = name2coords(src)\n",
    "        dst = name2coords(dst)\n",
    "\n",
    "        trace.src = trace.src.apply(name2coords)\n",
    "        trace.dst = trace.dst.apply(name2coords)\n",
    "\n",
    "        # Split column, row\n",
    "        trace['srcRow'], trace['srcCol'] = src\n",
    "        trace['dstRow'], trace['dstCol'] = dst\n",
    "\n",
    "        # Preserve sequence number\n",
    "        trace['seq'] = trace.index\n",
    "\n",
    "        trace['rss'] = trace.rssi + RSSI_BASE\n",
    "\n",
    "        trace['d'] = trace[['src', 'dst']].apply(get_distance, axis=1)\n",
    "        \n",
    "        trace['meanRSSI'] = trace.rssi.rolling(window=Wh).mean()\n",
    "        trace['medianRSSI'] = trace.rssi.rolling(window=Wh).median()\n",
    "        trace['stdRSSI'] = trace.rssi.rolling(window=Wh).std()\n",
    "        \n",
    "        trace['PRR'] = trace.received.rolling(window=Wprr).sum() / Wprr\n",
    "        \n",
    "        for i in range(1, predict_ahead+1):\n",
    "            trace[f'PRR+{i}'] = trace.PRR.shift(-Wprr * predict_ahead)\n",
    "\n",
    "        df.append(trace)\n",
    "        \n",
    "    df = pd.concat(df, ignore_index=True)\n",
    "    return df\n",
    "    \n",
    "produce_dataset().head(20)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 339x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot_map():\n",
    "    dataset = get_rutgers_datapoints()\n",
    "    \n",
    "    noise_generator_positions = pd.DataFrame(data=list(NOISE_SOURCES), columns=['row', 'col'])\n",
    "    noise_generator_positions['type'] = 'interference'\n",
    "\n",
    "    known_nodes = dataset.src.append(dataset.dst, ignore_index=True).unique().tolist()\n",
    "    known_nodes = pd.DataFrame(data=known_nodes, columns=['row', 'col'])\n",
    "    known_nodes['type'] = 'node'\n",
    "\n",
    "    positions = pd.concat([noise_generator_positions, known_nodes], ignore_index=True).reset_index(drop=True)\n",
    "\n",
    "    latexify(fig_height=8) # This one is a bit special\n",
    "    f, ax = plt.subplots()\n",
    "\n",
    "    sns.scatterplot(data=positions, x='col', y='row', style='type', hue='type', markers=['^','o'], ax=ax, legend=None)\n",
    "    ax.set_aspect('equal', 'box')\n",
    "\n",
    "    ax.set_xlabel(None)\n",
    "    ax.set_ylabel(None)\n",
    "\n",
    "    ax.invert_yaxis()\n",
    "\n",
    "    ax.set_xticks(np.arange(1, 9, 1))\n",
    "    ax.set_yticks(np.arange(1, 9, 1))\n",
    "    \n",
    "    ax.set_xlim([.5, 8.5])\n",
    "    ax.set_ylim([.5, 8.5])\n",
    "    \n",
    "    ax.set_ylabel('x (row)')\n",
    "    ax.set_xlabel('y (col)')\n",
    "\n",
    "    #ax.grid(which='major', color='0.9', linestyle=':')\n",
    "    ax.grid()\n",
    "\n",
    "    #sns.despine(f, ax)\n",
    "    format_axes(ax)\n",
    "\n",
    "    #f.savefig(ensure_dir(f'{FIGURE_OUTPUT}/rutgers-map.pdf'))\n",
    "    plt.show(f)\n",
    "    plt.close(f)\n",
    "    \n",
    "    return f, ax\n",
    "    \n",
    "plot_map();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
